//
// Created by YE on 2024/2/17.
//
#include "executor.h"
#include "../machine/ych_state.h"

void initExecutor(Executor *executor, YState *y_state, PC pc, VMMemory *vmMemory) {
    executor->pc = pc;
    executor->object_gc_list = NULL;
    executor->mat_gc_list = NULL;
    executor->memory = vmMemory;
    executor->y_state = y_state;
    memset(executor->VM_S, 0, sizeof(executor->VM_S));
    memset(executor->VM_R, 0, sizeof(executor->VM_R));
}

void freeExecutor(Executor *executor) {
    gc(executor);
    executor->memory = NULL;
    executor->y_state = NULL;
    memset(executor->VM_S, 0, sizeof(executor->VM_S));
    memset(executor->VM_R, 0, sizeof(executor->VM_R));
}

void gc(Executor *executor) {
    while (executor->object_gc_list) {
        GCNode *pre = executor->object_gc_list->pre;
        switch (executor->object_gc_list->object->type) {
            case Ot_Mat:
                deleteMat(executor->object_gc_list->object->value.p);
                executor->object_gc_list->object->value.p = NULL;
                break;
            default:
                break;
        }
        free(executor->object_gc_list);
        executor->object_gc_list = pre;
    }
    memset(executor->memory->VM_TAG, 0, sizeof(executor->memory->VM_TAG));
}

static void appendGC(Executor *executor, Object *object, unsigned char *TAG) {
    if (!(*TAG)) {
        GCNode *pre = executor->object_gc_list;
        executor->object_gc_list = malloc(sizeof(GCNode));
        executor->object_gc_list->object = object;
        executor->object_gc_list->pre = pre;
        *TAG = True;
    }
}

static void gcMatList(Executor *executor) {
    while (executor->mat_gc_list) {
        MatGCNode *pre = executor->mat_gc_list->pre;
        deleteMat(executor->mat_gc_list->mat);
        free(executor->mat_gc_list);
        executor->mat_gc_list = pre;
    }
}

static void appendMatGC(Executor *executor, Mat *mat) {
    MatGCNode *pre = executor->mat_gc_list;
    mat->is_popp = 1;
    executor->mat_gc_list = malloc(sizeof(MatGCNode));
    executor->mat_gc_list->mat = mat;
    executor->mat_gc_list->pre = pre;
}

static void gcInnerMatList(CallState *call_state) {
    while (call_state->mat_gc_list) {
        MatGCNode *pre = call_state->mat_gc_list->pre;
        deleteMat(call_state->mat_gc_list->mat);
        free(call_state->mat_gc_list);
        call_state->mat_gc_list = pre;
    }
}

static void appendInnerMatGC(CallState *call_state, Mat *mat) {
    mat->is_popp = 1;
    MatGCNode *pre = call_state->mat_gc_list;
    call_state->mat_gc_list = malloc(sizeof(MatGCNode));
    call_state->mat_gc_list->mat = mat;
    call_state->mat_gc_list->pre = pre;
}

void throwExecutor(Executor *executor, int code) {
    Error error;
    error.code = EXCEPTION_RUNERROR;
    switch (code) {
        case EX_STORE_ERROR:
            copyString(&error.info, "RUNTIME STORE ERROR");
            break;
        case EX_COMPUTE_ERROR:
            copyString(&error.info, "RUNTIME COMPUTE ERROR");
            break;
        case EX_POINTER_ERROR:
            copyString(&error.info, "RUNTIME POINTER ERROR");
            break;
        default:
            copyString(&error.info, "RUNTIME ERROR");
    }
    pushErrorStack(&executor->y_state->errors, error);
    throw(EXCEPTION_RUNERROR);
}

static int matrixAdd(Object *t, Mat *a, Mat *b) {
    if (a->rows != b->rows || a->cols != b->cols)return False;
    t->type = Ot_Mat;
    t->value.p = createMat(a->rows, a->cols);
    matAdd(((Mat *) t->value.p)->values, a->values, b->values, a->rows, a->cols);
    return True;
}

static int matrixSub(Object *t, Mat *a, Mat *b) {
    if (a->rows != b->rows || a->cols != b->cols)return False;
    t->type = Ot_Mat;
    t->value.p = createMat(a->rows, a->cols);
    matSub(((Mat *) t->value.p)->values, a->values, b->values, a->rows, a->cols);
    return True;
}

static int matrixMul(Object *t, Mat *a, Float f) {
    t->type = Ot_Mat;
    t->value.p = createMat(a->rows, a->cols);
    matMul(((Mat *) t->value.p)->values, a->values, f, a->rows, a->cols);
    return True;
}

static int matrixDiv(Object *t, Mat *a, Float f) {
    t->type = Ot_Mat;
    t->value.p = createMat(a->rows, a->cols);
    matDiv(((Mat *) t->value.p)->values, a->values, f, a->rows, a->cols);
    return True;
}

static int matrixImul(Object *t, Mat *a, Mat *b) {
    t->type = Ot_Mat;
    t->value.p = createMat(a->rows, b->cols);

    if (a->rows * b->cols * a->cols >= 58*58*58) {
        matInnerThread(((Mat *) t->value.p)->values, a->values, b->values, a->rows, b->cols, a->cols);
    } else {
        matInner(((Mat *) t->value.p)->values, a->values, b->values, a->rows, b->cols, a->cols);
    }
    return True;
}

static int matrixPow(Object *t, Mat *a, Int n) {
    if (a->rows != a->cols || n < 0)return False;
    t->type = Ot_Mat;
    t->value.p = createMat(a->rows, a->cols);
    matPow(((Mat *) t->value.p)->values, a->values, n, a->rows);
    return True;
}

static int matrixEq(Mat *a, Mat *b) {
    if (a->rows != a->cols || b->rows != b->cols)return False;
    return matEq(a->values, b->values, a->rows, a->cols);
}

void runExecutor(Executor *executor) {
    Object *MEM = executor->memory->VM_MEN;
    Object *STACK_TOP = executor->VM_S;
    Object *R = executor->VM_R;
    unsigned char *TAG = executor->memory->VM_TAG;
    Object *RB = R, *RC = R + 1;
    IX IX_0, IX_1;
    PC pc = executor->pc;
    Int *INT_MEM = executor->memory->VM_INT_CONST;
    Float *FLOAT_MEM = executor->memory->VM_FLOAT_CONST;
    String *STR_MEN = executor->memory->VM_STR_CONST;
    void **C_FUNC_MEN = executor->memory->VM_C_FUNC;
    OPCODE i;
    Uint opcode, k, a, b, c;
    CallState *call_state = NULL;
    CallState *temp_call_state = NULL;
    Mat *R_MAT;
    Object *object;
    while (True) {
        i = *pc;
        opcode = GET_OPCODE(i);
        switch (opcode) {
            case OP_END:
                executor->pc = pc;
                return;
            case OP_MOVS:
                a = GET_ARG_A(i);
                R[a] = *(STACK_TOP--);
                break;
            case OP_STORE:
                a = GET_ARG_A(i), b = GET_ARG_Bx(i);
                if (call_state) {
                    if (call_state->param_stack_start[b].type == Ot_Mat) {
                        deleteMat(call_state->param_stack_start[b].value.p);
                    }
                    call_state->param_stack_start[b] = R[a];
                    if (R[a].type == Ot_Mat) {
                        call_state->param_stack_start[b].value.p = copyMat(R[a].value.p);
                        gcInnerMatList(call_state);
                    }
                } else {
                    if (MEM[b].type == Ot_Mat) {
                        appendMatGC(executor, MEM[b].value.p);
                    }
                    MEM[b] = R[a];
                    if (R[a].type == Ot_Mat) {
                        MEM[b].value.p = copyMat(R[a].value.p);
                        appendGC(executor, MEM + b, TAG + b);
                        gcMatList(executor);
                    }
                }
                break;
            case OP_LOAD:
                a = GET_ARG_A(i), b = GET_ARG_Bx(i);
                R[a] = call_state ? call_state->param_stack_start[b] : MEM[b];
                break;
            case OP_LOAD_CONST:
                k = GET_ARG_K(i), a = GET_ARG_A(i), b = GET_ARG_Bx(i);
                switch (k) {
                    case LOAD_CONST_INT:
                        R[a].value.i = INT_MEM[b], R[a].type = Ot_Int;
                        break;
                    case LOAD_CONST_FLOAT:
                        R[a].value.f = FLOAT_MEM[b], R[a].type = Ot_Float;
                        break;
                    case LOAD_CONST_BOOL:
                        R[a].value.b = b, R[a].type = Ot_Bool;
                        break;
                    case LOAD_CONST_STRING:
                        R[a].value.p = STR_MEN + b, R[a].type = Ot_String;
                        break;
                }
                break;
            case OP_POP:
                --STACK_TOP;
                if (executor->mat_gc_list) {
                    gcMatList(executor);
                    if (call_state)gcInnerMatList(call_state);
                }
                break;
            case OP_PUSH:
                a = GET_ARG_A(i);
                *(++STACK_TOP) = R[a];
                break;
            case OP_ADD:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.i + RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.i + RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.i = RB->value.i + RC->value.b;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.i + *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = RB->value.f + RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.f + RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = RB->value.f + RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.i + *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.b + RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.b + RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b + RC->value.b;
                                STACK_TOP->type = Ot_Bool;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.b + *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = *(Float *) RB->value.p + RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = *(Float *) RB->value.p + RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = *(Float *) RB->value.p + RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = *(Float *) RC->value.p + *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Mat:
                                matrixAdd(STACK_TOP, RB->value.p, RC->value.p);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_SUB:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.i - RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.i - RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.i = RB->value.i - RC->value.b;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.i - *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = RB->value.f - RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.f - RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = RB->value.f - RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.f - *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.b - RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.b - RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b - RC->value.b;
                                STACK_TOP->type = Ot_Bool;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.b - *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = *(Float *) RB->value.p - RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = *(Float *) RB->value.p - RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = *(Float *) RB->value.p - RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = *(Float *) RB->value.p - *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Mat:
                                matrixSub(STACK_TOP, RB->value.p, RC->value.p);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_MUL:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.i * RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.i * RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.i = RB->value.i * RC->value.b;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.i * *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Mat:
                                matrixMul(STACK_TOP, RC->value.p, RB->value.i);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = RB->value.f * RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.f * RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = RB->value.f * RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.f * *(Float *) RC->value.p;
                                break;
                            case Ot_Mat:
                                matrixMul(STACK_TOP, RC->value.p, RB->value.f);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.b * RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.b * RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b * RC->value.b;
                                STACK_TOP->type = Ot_Bool;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.b * *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Mat:
                                matrixMul(STACK_TOP, RC->value.p, RB->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = *(Float *) RB->value.p * RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = *(Float *) RB->value.p * RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = *(Float *) RB->value.p * RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = *(Float *) RB->value.p * *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Int:
                                matrixMul(STACK_TOP, RB->value.p, RC->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            case Ot_Float:
                                matrixMul(STACK_TOP, RB->value.p, RC->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            case Ot_Bool:
                                matrixMul(STACK_TOP, RB->value.p, RC->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            case Ot_Mat_V:
                                matrixMul(STACK_TOP, RB->value.p, *(Float *) RC->value.p);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_IMUL:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Mat:
                                if (((Mat *) RB->value.p)->cols != ((Mat *) RC->value.p)->rows) {
                                    throwExecutor(executor, EX_COMPUTE_ERROR);
                                }
                                matrixImul(STACK_TOP, RB->value.p, RC->value.p);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_DIV:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.i / RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.i / RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.i = RB->value.i / RC->value.b;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.i / *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Mat:
                                matrixDiv(STACK_TOP, RC->value.p, RB->value.i);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = RB->value.f / RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.f / RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = RB->value.f / RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.f / *(Float *) RC->value.p;
                                break;
                            case Ot_Mat:
                                matrixDiv(STACK_TOP, RC->value.p, RB->value.f);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.b / RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = RB->value.b / RC->value.f;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b / RC->value.b;
                                STACK_TOP->type = Ot_Bool;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = RB->value.f / *(Float *) RC->value.p;
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Mat:
                                matrixDiv(STACK_TOP, RC->value.p, RB->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = *(Float *) RB->value.p / RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = *(Float *) RB->value.p / RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = *(Float *) RB->value.p / RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = *(Float *) RB->value.p / *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Int:
                                matrixDiv(STACK_TOP, RB->value.p, RC->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            case Ot_Float:
                                matrixDiv(STACK_TOP, RB->value.p, RC->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            case Ot_Bool:
                                matrixDiv(STACK_TOP, RB->value.p, RC->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            case Ot_Mat_V:
                                matrixDiv(STACK_TOP, RB->value.p, *(Float *) RC->value.p);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_MOD:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Int:
                        STACK_TOP->type = Ot_Int;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.i % RC->value.i;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.i = RB->value.i % RC->value.b;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = RB->value.b % RC->value.i;
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b % RC->value.b;
                                STACK_TOP->type = Ot_Bool;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_POW:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = pow(RB->value.i, RC->value.i);
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = pow(RB->value.i, RC->value.f);
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.i = pow(RB->value.i, RC->value.b);
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = pow(RB->value.i, *(Float *) RC->value.p);
                                STACK_TOP->type = Ot_Float;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = pow(RB->value.f, RC->value.i);
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = pow(RB->value.f, RC->value.f);
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = pow(RB->value.f, RC->value.b);
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = pow(RB->value.f, *(Float *) RC->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.i = pow(RB->value.b, RC->value.i);
                                STACK_TOP->type = Ot_Int;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = pow(RB->value.b, RC->value.f);
                                STACK_TOP->type = Ot_Float;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = pow(RB->value.b, RC->value.b);
                                STACK_TOP->type = Ot_Bool;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = pow(RB->value.b, *(Float *) RC->value.p);
                                STACK_TOP->type = Ot_Float;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        STACK_TOP->type = Ot_Float;
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.f = pow(*(Float *) RB->value.p, RC->value.i);
                                break;
                            case Ot_Float:
                                STACK_TOP->value.f = pow(*(Float *) RB->value.p, RC->value.f);
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.f = pow(*(Float *) RB->value.p, RC->value.b);
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.f = pow(*(Float *) RB->value.p, *(Float *) RC->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Int:
                                matrixPow(STACK_TOP, RB->value.p, RC->value.i);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            case Ot_Bool:
                                matrixPow(STACK_TOP, RB->value.p, RC->value.b);
                                call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                            STACK_TOP->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_NEG:
                ++STACK_TOP;
                switch (RB->type) {
                    case Ot_Int:
                        STACK_TOP->value.i = -RB->value.i;
                        STACK_TOP->type = Ot_Int;
                        break;
                    case Ot_Float:
                        STACK_TOP->value.f = -RB->value.f;
                        STACK_TOP->type = Ot_Float;
                        break;
                    case Ot_Bool:
                        STACK_TOP->value.b = -RB->value.b;
                        STACK_TOP->type = Ot_Bool;
                    case Ot_Mat_V:
                        STACK_TOP->value.f = -*(Float *) RC->value.p;
                        STACK_TOP->type = Ot_Float;
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_LESS:
                ++STACK_TOP;
                STACK_TOP->type = Ot_Bool;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.i < RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.i < RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.i < RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.i < *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.f < RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.f < RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.f < RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.f < *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.b < RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.b < RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b < RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.b < *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = *(Float *) RB->value.p < RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = *(Float *) RB->value.p < RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = *(Float *) RB->value.p < RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = *(Float *) RB->value.p < *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_LESSEQUAL:
                ++STACK_TOP;
                STACK_TOP->type = Ot_Bool;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.i <= RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.i <= RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.i <= RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.i <= *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.f <= RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.f <= RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.f <= RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.f <= *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.b <= RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.b <= RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b <= RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.b <= *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = *(Float *) RB->value.p <= RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = *(Float *) RB->value.p <= RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = *(Float *) RB->value.p <= RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = *(Float *) RB->value.p <= *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_EQUAL:
                ++STACK_TOP;
                STACK_TOP->type = Ot_Bool;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.i == RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.i == RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.i == RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.i == *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.f == RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.f == RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.f == RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.f == *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.b == RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.b == RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b == RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.b == *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = *(Float *) RB->value.p == RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = *(Float *) RB->value.p == RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = *(Float *) RB->value.p == RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = *(Float *) RB->value.p == *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Mat:
                                STACK_TOP->value.b = matrixEq(RB->value.p, RC->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_NOTEQUAL:
                ++STACK_TOP;
                STACK_TOP->type = Ot_Bool;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.i != RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.i != RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.i != RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.i != *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Float:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.f != RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.f != RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.f != RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.f != *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.b != RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = RB->value.b != RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b != RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = RB->value.b != *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat_V:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = *(Float *) RB->value.p != RC->value.i;
                                break;
                            case Ot_Float:
                                STACK_TOP->value.b = *(Float *) RB->value.p != RC->value.f;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = *(Float *) RB->value.p != RC->value.b;
                                break;
                            case Ot_Mat_V:
                                STACK_TOP->value.b = *(Float *) RB->value.p != *(Float *) RC->value.p;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Mat:
                        switch (RC->type) {
                            case Ot_Mat:
                                STACK_TOP->value.b = !matrixEq(RB->value.p, RC->value.p);
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_NOT:
                ++STACK_TOP;
                STACK_TOP->type = Ot_Bool;
                switch (RB->type) {
                    case Ot_Int:
                        STACK_TOP->value.b = !RB->value.i;
                        break;
                    case Ot_Float:
                        STACK_TOP->value.b = !RB->value.f;
                        break;
                    case Ot_Bool:
                        STACK_TOP->value.b = !RB->value.b;
                        break;
                    case Ot_Mat_V:
                        STACK_TOP->value.b = !*(Float *) RC->value.p;
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_AND:
                ++STACK_TOP;
                STACK_TOP->type = Ot_Bool;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.i & RC->value.i;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.i & RC->value.b;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.b & RC->value.i;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b & RC->value.b;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_OR:
                ++STACK_TOP;
                STACK_TOP->type = Ot_Bool;
                switch (RB->type) {
                    case Ot_Int:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.i | RC->value.i;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.i | RC->value.b;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    case Ot_Bool:
                        switch (RC->type) {
                            case Ot_Int:
                                STACK_TOP->value.b = RB->value.b | RC->value.i;
                                break;
                            case Ot_Bool:
                                STACK_TOP->value.b = RB->value.b | RC->value.b;
                                break;
                            default:
                                throwExecutor(executor, EX_COMPUTE_ERROR);
                        }
                        break;
                    default:
                        throwExecutor(executor, EX_COMPUTE_ERROR);
                }
                break;
            case OP_CJUMP:
                b = GET_ARG_Bx(i);
                if (!R->value.b) pc += b;
                break;
            case OP_JUMP:
                k = GET_ARG_K(i), b = GET_ARG_Bx(i);
                switch (k) {
                    case JUMP_F:
                        pc += b;
                        break;
                    case JUMP_R:
                        pc -= b;
                        break;
                }
                break;
            case OP_MOV:
                k = GET_ARG_K(i), b = GET_ARG_B(i), c = GET_ARG_C(i);
                switch (k) {
                    case MOV_NORMAL:
                        R[b] = R[c];
                        break;
                    case MOV_T:
                        R[b].type = Ot_T;
                        break;
                    case MOV_MATV:
                        switch (R[4].type) {
                            case Ot_Int:
                                R_MAT->values[IX_0][IX_1++] = R[4].value.i;
                                break;
                            case Ot_Float:
                                R_MAT->values[IX_0][IX_1++] = R[4].value.f;
                                break;
                            case Ot_Bool:
                                R_MAT->values[IX_0][IX_1++] = R[4].value.b;
                                break;
                            default:
                                throwExecutor(executor, EX_STORE_ERROR);
                                return;
                        }
                        break;
                }
                break;
            case OP_CALL:
                a = GET_ARG_A(i), b = GET_ARG_Bx(i);
                temp_call_state = call_state;
                call_state = malloc(sizeof(CallState));
                call_state->pre = temp_call_state;
                call_state->param_stack_start = STACK_TOP - a + 1;
                call_state->return_ip = pc;
                call_state->mat_gc_list = NULL;
                pc = executor->memory->VM_I + b;
                break;
            case OP_LEV:
                pc = call_state->return_ip;
                temp_call_state = call_state;
                call_state = call_state->pre;
                free(temp_call_state);
                break;
            case OP_PUSHP:
                a = GET_ARG_A(i);
                *(++STACK_TOP) = R[a];
                if (R[a].type == Ot_Mat) {
                    STACK_TOP->value.p = copyMat(R[a].value.p);
                }
                break;
            case OP_POPP:
                if (STACK_TOP->type == Ot_Mat && !((Mat *) STACK_TOP->value.p)->is_popp) {
                    call_state ? appendInnerMatGC(call_state, STACK_TOP->value.p) : appendMatGC(executor,
                                                                                                STACK_TOP->value.p);
                }
                --STACK_TOP;
                break;
            case OP_CALLC:
                a = GET_ARG_A(i), b = GET_ARG_Bx(i);
                ++STACK_TOP;
                switch (a) {
                    case CFT_O0:
                        *STACK_TOP = ((CFO0) C_FUNC_MEN[b])();
                        break;
                    case CFT_O1:
                        *STACK_TOP = ((CFO1) C_FUNC_MEN[b])(call_state->param_stack_start);
                        break;
                    case CFT_V2:
                        ((CFV2) C_FUNC_MEN[b])(call_state->param_stack_start,
                                               call_state->param_stack_start + 1);
                        STACK_TOP->type = Ot_None;
                        break;
                    case CFT_O2:
                        *STACK_TOP = ((CFO2) C_FUNC_MEN[b])(call_state->param_stack_start,
                                                            call_state->param_stack_start + 1);
                        break;
                    case CFT_O4:
                        *STACK_TOP = ((CFO4) C_FUNC_MEN[b])(call_state->param_stack_start,
                                                            call_state->param_stack_start + 1,
                                                            call_state->param_stack_start + 2,
                                                            call_state->param_stack_start + 3);
                        break;
                }
                break;
            case OP_MALLOC:
                k = GET_ARG_K(i), a = GET_ARG_A(i);
                switch (k) {
                    case MALLOC_MAT:
                        IX_0 = 0, IX_1 = 0;
                        R[a].type = Ot_Mat;
                        R[a].value.p = R_MAT = createMat(R[0].value.b, R[1].value.b);
                        call_state ? appendInnerMatGC(call_state, R_MAT) : appendMatGC(executor, R_MAT);
                        break;
                    case MALLOC_LIST:
                        b = GET_ARG_Bx(i);
                        R[a].type = Ot_List;
                        R[a].value.p = call_state ? call_state->param_stack_start + b : MEM + b;
                        break;
                }
                break;
            case OP_INC:
                ++IX_0, IX_1 = 0;
                break;
            case OP_INDEX:
                ++STACK_TOP;
                if (RB->type != Ot_List || RC->type != Ot_Int) {
                    throwExecutor(executor, EX_POINTER_ERROR);
                    return;
                }
                STACK_TOP->type = Ot_P;
                STACK_TOP->value.p = (Object *) RB->value.p + RC->value.i;
                break;
            case OP_LOAD_P:
                a = GET_ARG_A(i);
                R[a] = *(Object *) (STACK_TOP--)->value.p;
                break;
            case OP_ASSIGN_P:
                a = GET_ARG_A(i);
                object = STACK_TOP->value.p;
                if (object->type == Ot_Mat) {
                    appendMatGC(executor, object->value.p);
                }
                *object = R[a];
                if (R[a].type == Ot_Mat) {
                    MEM[b].value.p = copyMat(R[a].value.p);
                    appendGC(executor, MEM + b, TAG + b);
                    gcMatList(executor);
                }
                break;
            case OP_MAT_INDEX:
                b = GET_ARG_Bx(i);
                R[1] = *(STACK_TOP--);
                R[0] = *STACK_TOP;
                R[2] = call_state ? call_state->param_stack_start[b] : MEM[b];
                if (R[0].type != Ot_Int || R[1].type != Ot_Int || R[2].type != Ot_Mat)
                    throwExecutor(executor, EX_COMPUTE_ERROR);
                STACK_TOP->type = Ot_Mat_V;
                STACK_TOP->value.p = ((Mat *) R[2].value.p)->values[R[0].value.i] + R[1].value.i;
                break;
            case OP_MAT_ASSIGN:
                a = GET_ARG_A(i);
                switch (R[a].type) {
                    case Ot_Int:
                        *((Float *) STACK_TOP->value.p) = R[a].value.i;
                        break;
                    case Ot_Float:
                        *((Float *) STACK_TOP->value.p) = R[a].value.f;
                        break;
                    case Ot_Bool:
                        *((Float *) STACK_TOP->value.p) = R[a].value.b;
                        break;
                    case Ot_Mat_V:
                        *((Float *) STACK_TOP->value.p) = *((Float *) R[a].value.p);
                        break;
                    default:
                        throwExecutor(executor, EX_STORE_ERROR);
                }
                break;
            default:
                return;
        }
        pc++;
    }
}